package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;

import view.MainFrame;
import model.DistributionGenerator;
import model.FrequencyPair;
import model.MeanVarianceCalculator;
import model.SampleGenerator;

public class Controller {
	
	private MainFrame mainFrame;
	private ArrayList<FrequencyPair> freqDist;
	private ArrayList<FrequencyPair> meanDist;
	
	private HashMap<Integer, ArrayList<FrequencyPair>> historyFreqDist;
	private HashMap<Integer, ArrayList<FrequencyPair>> historyMeanDist;
	
	private int curr_lb;
	private int curr_ub;
	private int curr_N;
	private int curr_n;
	
	public Controller(){
		mainFrame = new MainFrame();
		mainFrame.setVisible(true);
		
		mainFrame.setBtnGeneratePopulationListener(new GeneratePopulationActionListener(0));
		mainFrame.setBtnGenerateSampleMeanDistListener(new GenerateSampleMeanActionListener(0));
		mainFrame.setBtnPopDec(new GeneratePopulationActionListener(-1));
		mainFrame.setBtnPopInc(new GeneratePopulationActionListener(1));
		mainFrame.setBtnSampDec(new GenerateSampleMeanActionListener(-1));
		mainFrame.setBtnSampInc(new GenerateSampleMeanActionListener(1));
		mainFrame.setBtnChange(new ChangeIntervalActionListener());
		
		freqDist = null;
		meanDist = null;
		historyFreqDist = null;
		historyMeanDist = null;
		curr_N = 0;
		curr_n = 0;
		curr_lb = 0;
		curr_ub = 0;
	}
	
	public boolean isPopInputChanged(int LB, int UB, int N){
		if(curr_lb == LB && curr_ub == UB && curr_N == N)
			return false;
		else
			return true;
	}
	
	public boolean isPopInputChanged(int LB, int UB, int N, int n){
		if(isPopInputChanged( LB, UB, N) && curr_n == n)
			return false;
		else
			return true;
	}
	
	private void generatePopulation(int mode){
		try {
			if(mode == -1)
				mainFrame.offset_N(mainFrame.get_Interval() * -1);
			else if(mode == 1)
				mainFrame.offset_N(mainFrame.get_Interval());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if(mainFrame.isInputValidForGeneratePopulation()){	
			String type = mainFrame.getDistributionType();
			
			try{
				if(type.equals(mainFrame.RANDOM))
					freqDist = DistributionGenerator.generateRandom(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N());
				else if(type.equals(mainFrame.UNIFORM))
					freqDist = DistributionGenerator.generateUniform(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N());
				else if(type.equals(mainFrame.SKEWED_LEFT))
					freqDist = DistributionGenerator.generateSkewed(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N(),true);
				else if(type.equals(mainFrame.SKEWED_RIGHT))
					freqDist = DistributionGenerator.generateSkewed(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N(),false);
				else if(type.equals(mainFrame.BIMODAL))
					freqDist = DistributionGenerator.generateBimodal(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N());
				else if(type.equals(mainFrame.NORMAL))
					freqDist = DistributionGenerator.generateNormal(mainFrame.get_LB(), mainFrame.get_UB(), mainFrame.get_N());
			}
			catch(Exception ex){};
			
			if(freqDist != null){
				mainFrame.setPopDistTableContent(freqDist);
				mainFrame.setPopulationGraphContent(freqDist);
				mainFrame.setTfPopMean(MeanVarianceCalculator.calculateMean(freqDist));
				mainFrame.setTfPopVar(MeanVarianceCalculator.calculateVariance(freqDist,true));
			}
		}
	}
	
	private void generateSampleMean(int offset){
		try {
			mainFrame.offset_n(offset);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if(freqDist == null && mainFrame.isInputValidForGeneratePopulation())
			generatePopulation(0);
		if(freqDist != null && mainFrame.isInputValidForGenerateSample()){
			try {
				meanDist = SampleGenerator.generateSampleMeanDistribution(freqDist, mainFrame.get_n());
			} catch (Exception ex){};
			
			if(meanDist != null){
				mainFrame.setSampleGraphContent(meanDist);
				mainFrame.setTfSampMean(MeanVarianceCalculator.calculateMean(freqDist));
				mainFrame.setTfSampVar(MeanVarianceCalculator.calculateVariance(freqDist,true));
			}
		}
	}
	
	private void changeInterval(){
		try 
		{
			int interval = mainFrame.get_Interval();
			
			if(interval > 0)
				mainFrame.set_Interval(interval);
			else
				mainFrame.displayError("Interval must be a positive integer");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	class GeneratePopulationActionListener implements ActionListener {
		int mode = 0;
		
		public GeneratePopulationActionListener(int mode){
			this.mode = mode;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			generatePopulation(mode);
		}	
	}
	
	class GenerateSampleMeanActionListener implements ActionListener {
		int offset = 0;
		
		public GenerateSampleMeanActionListener(int offset){
			this.offset = offset;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			generateSampleMean(offset);
		}	
	}
	
	class ChangeIntervalActionListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			changeInterval();
		}
	}
}
